﻿//统一文件为utf-8编码编译
#pragma execution_character_set("utf-8")
///////////////////////////////////////////////////////////////////////////
// 文件名:     qudpsocketclient.cpp
// 描述:
// 作者:      颜磊
// 创建时间:   2024-06-08 23:46
///////////////////////////////////////////////////////////////////////////
#include "qudpsocketclient.h"
#include "networkstruct.h"

#include <QNetworkDatagram>

QUdpSocketClient::QUdpSocketClient(QString m_localAddress,uint16_t m_localPort,QString m_desAddress,uint16_t m_desPort,QObject *parent) : QThread(parent)
{
    moveToThread(this);
    qRegisterMetaType<uint64_t>("uint64_t");
    qRegisterMetaType<QByteArray>("QByteArray");
    connect(this,&QUdpSocketClient::signal_openSocket,this,&QUdpSocketClient::slot_openSocket);
    connect(this,&QUdpSocketClient::signal_closeSocket,this,&QUdpSocketClient::slot_closeSocket);
    localAddress = m_localAddress;
    localPort = m_localPort;
    desAddress = m_desAddress;
    desPort = m_desPort;

    sendPackId = 0;
    nextFrameSerial = 0;
    start();
}

QUdpSocketClient::~QUdpSocketClient()
{
    quit();
    wait();
}

void QUdpSocketClient::open()
{
    signal_openSocket();
}

void QUdpSocketClient::close()
{
    signal_closeSocket();
}

void QUdpSocketClient::slot_openSocket()
{
    udpSocket = new QUdpSocket();
    udpSocket->bind(localPort);
    udpSocket->connectToHost(desAddress,desPort);
    connect(udpSocket,&QUdpSocket::readyRead,this,&QUdpSocketClient::readyRead);
}

void QUdpSocketClient::slot_closeSocket()
{
    udpSocket->close();
    delete udpSocket;
}

uint16_t QUdpSocketClient::getSendPackId()
{
    return sendPackId++;
}

void QUdpSocketClient::run()
{
    exec();
}

void QUdpSocketClient::readyRead()
{
    QByteArray byteArray = udpSocket->receiveDatagram().data();
    parsingFrameData(byteArray);
}

void QUdpSocketClient::slot_sendData(QByteArray byteArray)
{
    QByteArray sendByteArray;
    sendByteArray.resize(UDP_SOCKET_FRAME_LEN);
    int sendDataLen = UDP_SOCKET_FRAME_LEN - sizeof(UdpSocketFrameHeader);
    UdpSocketFrameHeader udpSocketFrameHeader;
    udpSocketFrameHeader.packId = getSendPackId();
    udpSocketFrameHeader.packLen = byteArray.size();
    udpSocketFrameHeader.frameSerial = 0;//帧序号

    while(byteArray.size() > 0){
        udpSocketFrameHeader.dataLen = byteArray.size() > sendDataLen ? sendDataLen : byteArray.size();
        if(byteArray.size() <= sendDataLen){
            udpSocketFrameHeader.frameMark = FRAME_MARK_END;
        }else{
            udpSocketFrameHeader.frameMark = FRAME_MARK_CENTER;
        }
        memcpy(sendByteArray.data(),&udpSocketFrameHeader,sizeof(SocketFrameHeader));
        memcpy(sendByteArray.data() + sizeof(SocketFrameHeader),byteArray.data(),byteArray.size() > sendDataLen ? sendDataLen : byteArray.size());
        udpSocket->writeDatagram(QNetworkDatagram(sendByteArray,QHostAddress(desAddress),desPort));
        byteArray.remove(0,byteArray.size() > sendDataLen ? sendDataLen : byteArray.size());
        udpSocketFrameHeader.frameSerial++;
        QThread::msleep(1);
    }
}

void QUdpSocketClient::parsingFrameData(const QByteArray &byteArray)
{
    recvFrameTempData.append(byteArray);
    while(recvFrameTempData.size() >= UDP_SOCKET_FRAME_LEN){
        UdpSocketFrameHeader udpSocketFrameHeader;
        if(recvFrameTempData.size() < sizeof (udpSocketFrameHeader)){
            qCritical() << __FUNCTION__ << "The frame data is less than the frame header length.";
            //return;
        }
        memcpy(&udpSocketFrameHeader,recvFrameTempData,sizeof (udpSocketFrameHeader));

        if(udpSocketFrameHeader.syncMark != UDP_SYNC_MARK){
            qCritical() << __FUNCTION__ << "Sync mark error in frame header.";
            //return;
        }

        if(udpSocketFrameHeader.packId != recvPackId){
            //qCritical() << __FUNCTION__ << "packId != recvPackId";
            recvPackData.clear();
            recvPackId = udpSocketFrameHeader.packId;
            nextFrameSerial = 0;
        }

        if(udpSocketFrameHeader.frameSerial != nextFrameSerial){
            //qCritical() << __FUNCTION__ << "The frame number does not match." << udpSocketFrameHeader.frameSerial << nextFrameSerial;
            //return;
        }

        nextFrameSerial++;

        QByteArray frameData;
        frameData.resize(udpSocketFrameHeader.dataLen);
        memcpy(frameData.data(),recvFrameTempData.data()+sizeof (udpSocketFrameHeader),udpSocketFrameHeader.dataLen);
        recvPackData.append(frameData);


        if(udpSocketFrameHeader.frameMark == FRAME_MARK_END){
            if(udpSocketFrameHeader.packLen != recvPackData.size()){
                qCritical() << __FUNCTION__ << "The packet length does not match.";
                //return;
            }else{
                //start dispose pack data
                emit signal_recvData(recvPackData);
            }
            nextFrameSerial = 0;
            recvPackData.clear();
        }
        recvFrameTempData.remove(0,TCP_SOCKET_FRAME_LEN);
    }
}
